package top.v5it.japi.plus.data.jdbc.service;

import cn.hutool.core.collection.CollUtil;
import org.apache.ibatis.session.ResultHandler;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import top.v5it.japi.plus.data.jdbc.mybatis.AbstractMybatisDTO;
import top.v5it.japi.plus.data.jdbc.repository.JapiJdbcAndMybatisRepository;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * @author zhanpu
 * @date 2022/8/3
 */
public interface JapiMybatisService<T, ID> {

    /**
     * 默认批量处理上限数
     */
    int DEFAULT_BATCH_SIZE = 1000;

    /**
     * 事务模板
     *
     * @return
     */
    TransactionTemplate getTransactionTemplate();

    /**
     * @return
     * @see JapiJdbcAndMybatisRepository
     */
    JapiJdbcAndMybatisRepository<T, ID> getJapiRepository();

    /**
     * 采用mybatis修改
     *
     * @param entity
     * @param <S>
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default <S extends T> int modify(S entity) {
        return getJapiRepository().update(entity);
    }

    /**
     * 采用mybatis修改
     *
     * @param dto
     * @param <D>
     * @return
     * @see AbstractMybatisDTO
     */
    @Transactional(rollbackFor = Exception.class)
    default <D extends AbstractMybatisDTO> int modifyByParameterDto(D dto) {
        return getJapiRepository().updateByParameterDto(dto);
    }

    /**
     * 采用mybatis修改
     *
     * @param paramMap
     * @return
     * @see Map
     */
    @Transactional(rollbackFor = Exception.class)
    default int modifyByMapParameter(Map<String, ?> paramMap) {
        return getJapiRepository().updateByMapParameter(paramMap);
    }

    /**
     * 采用mybatis批量新增
     *
     * @param entities
     * @param <S>
     * @return
     */
    default <S extends T> int addAllInBatch(Collection<S> entities) {
        return addAllInBatch(entities, DEFAULT_BATCH_SIZE);
    }

    /**
     * 采用mybatis批量新增，批次大小取决传递参数
     *
     * @param entities
     * @param batchSize
     * @param <S>
     * @return
     */
    default <S extends T> int addAllInBatch(Collection<S> entities, int batchSize) {
        return changeAllInBatch(entities, batchSize, getJapiRepository()::insertAllInBatch);
    }

    /**
     * 采用mybatis批量修改
     *
     * @param entities
     * @param <S>
     * @return
     */
    default <S extends T> int modifyAllInBatch(Collection<S> entities) {
        return modifyAllInBatch(entities, DEFAULT_BATCH_SIZE);
    }

    /**
     * 采用mybatis批量修改，批次大小取决传递参数
     *
     * @param entities
     * @param batchSize
     * @param <S>
     * @return
     */
    default <S extends T> int modifyAllInBatch(Collection<S> entities, int batchSize) {
        return changeAllInBatch(entities, batchSize, getJapiRepository()::updateAllInBatch);
    }

    /**
     * 采用mybatis批量移除
     *
     * @param entities
     * @param <S>
     * @return
     */
    default <S extends T> int removeAllInBatch(Collection<S> entities) {
        return removeAllInBatch(entities, DEFAULT_BATCH_SIZE);
    }

    /**
     * 采用mybatis批量移除，批次大小取决传递参数
     *
     * @param entities
     * @param batchSize
     * @param <S>
     * @return
     */
    default <S extends T> int removeAllInBatch(Collection<S> entities, int batchSize) {
        return changeAllInBatch(entities, batchSize, getJapiRepository()::deleteAllInBatch);
    }

    /**
     * 批量变更
     *
     * @param entities
     * @param batchSize
     * @param changeFunc
     * @param <S>
     * @return
     */
    default <S extends T> int changeAllInBatch(Collection<S> entities, int batchSize, Function<List<S>, Integer> changeFunc) {
        final List<List<S>> batch = CollUtil.split(entities, batchSize);
        Integer count = 0;

        for (List<S> s : batch) {
            final Integer rows = getTransactionTemplate().execute(status -> changeFunc.apply(s));
            count += rows;
        }

        return count;
    }

    /**
     * 采用mybatis搜索
     *
     * @param entity
     * @param <S>
     * @return
     */
    default <S extends T> List<S> searchAllByCondition(S entity) {
        return getJapiRepository().selectAllByCondition(entity);
    }

    /**
     * 采用mybatis搜索
     *
     * @param paramMap
     * @param <E>
     * @return
     */
    default <E> List<E> searchAllByMapCondition(Map<String, ?> paramMap) {
        return getJapiRepository().selectAllByMapCondition(paramMap);
    }

    /**
     * 采用mybatis搜索
     *
     * @param dto
     * @param <D>
     * @param <E>
     * @return
     */
    default <D extends AbstractMybatisDTO, E> List<E> searchAllByDtoCondition(D dto) {
        return getJapiRepository().selectAllByDtoCondition(dto);
    }

    /**
     * 采用mybatis搜索并分页返回
     *
     * @param entity
     * @param pageable
     * @param <S>
     * @param <E>
     * @return
     */
    default <S extends T, E> Page<E> searchAllByCondition(S entity, Pageable pageable) {
        return getJapiRepository().selectAllByCondition(entity, pageable);
    }

    /**
     * 采用mybatis搜索并分页返回
     *
     * @param paramMap
     * @param pageable
     * @param <E>
     * @return
     */
    default <E> Page<E> searchAllByMapCondition(Map<String, ?> paramMap, Pageable pageable) {
        return getJapiRepository().selectAllByMapCondition(paramMap, pageable);
    }

    /**
     * 采用mybatis搜索并分页返回
     *
     * @param dto
     * @param pageable
     * @param <D>
     * @param <E>
     * @return
     */
    default <D extends AbstractMybatisDTO, E> Page<E> searchAllByDtoCondition(D dto, Pageable pageable) {
        return getJapiRepository().selectAllByDtoCondition(dto, pageable);
    }

    /**
     * 采用mybatis搜索符合条件的单个实体
     *
     * @param entity
     * @param <S>
     * @param <E>
     * @return
     */
    default <S extends T, E> E searchOneByCondition(S entity) {
        return getJapiRepository().selectOneByCondition(entity);
    }

    /**
     * 采用mybatis搜索符合条件的单个实体
     *
     * @param paramMap
     * @param <E>
     * @return
     */
    default <E> E searchOneByMapCondition(Map<String, ?> paramMap) {
        return getJapiRepository().selectOneByMapCondition(paramMap);
    }

    /**
     * 采用mybatis搜索符合条件的单个实体
     *
     * @param dto
     * @param <D>
     * @param <E>
     * @return
     */
    default <D extends AbstractMybatisDTO, E> E searchOneByDtoCondition(D dto) {
        return getJapiRepository().selectOneByDtoCondition(dto);
    }

    /**
     * 采用mybatis搜索符合条件的单个实体并按mapKey字段返回
     *
     * @param entity
     * @param mapKey
     * @param <K>
     * @param <V>
     * @param <S>
     * @return
     */
    default <K, V, S extends T> Map<K, V> searchMapByCondition(S entity, String mapKey) {
        return getJapiRepository().selectMapByCondition(entity, mapKey);
    }

    /**
     * 采用mybatis搜索符合条件的单个实体并按mapKey字段返回
     *
     * @param paramMap
     * @param mapKey
     * @param <K>
     * @param <V>
     * @return
     */
    default <K, V> Map<K, V> searchMapByMapCondition(Map<String, ?> paramMap, String mapKey) {
        return getJapiRepository().selectMapByMapCondition(paramMap, mapKey);
    }

    /**
     * 采用mybatis搜索符合条件的单个实体并按mapKey字段返回
     *
     * @param dto
     * @param mapKey
     * @param <K>
     * @param <V>
     * @param <D>
     * @return
     */
    default <K, V, D extends AbstractMybatisDTO> Map<K, V> searchMapByDtoCondition(D dto, String mapKey) {
        return getJapiRepository().selectMapByDtoCondition(dto, mapKey);
    }

    /**
     * 采用mybatis搜索符合条件的{@link ResultHandler}交由用户自己处理结果
     *
     * @param entity
     * @param handler
     * @param <S>
     */
    default <S extends T> void searchAllByCondition(S entity, ResultHandler<?> handler) {
        getJapiRepository().selectAllByCondition(entity, handler);
    }

    /**
     * 采用mybatis搜索符合条件的{@link ResultHandler}交由用户自己处理结果
     *
     * @param paramMap
     * @param handler
     */
    default void searchAllByMapCondition(Map<String, ?> paramMap, ResultHandler<?> handler) {
        getJapiRepository().selectAllByMapCondition(paramMap, handler);
    }

    /**
     * 采用mybatis搜索符合条件的{@link ResultHandler}交由用户自己处理结果
     *
     * @param dto
     * @param handler
     * @param <D>
     */
    default <D extends AbstractMybatisDTO> void searchAllByDtoCondition(D dto, ResultHandler<?> handler) {
        getJapiRepository().selectAllByDtoCondition(dto, handler);
    }

}
